package com.bungarus.busi;

import com.bungarus.Busi;
import com.bungarus.codec.protobuf.MessageProtobuf;
import com.bungarus.model.MessageBuilder;
import com.bungarus.model.MessageType;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.log4j.Logger;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by tang on 2018/11/25.
 */
public class ProcessMessageHandler extends ChannelInboundHandlerAdapter {
    Logger logger = Logger.getLogger(ProcessMessageHandler.class);
    private Busi busServer;

    public ProcessMessageHandler(Busi busServer) {
        this.busServer = busServer;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof MessageProtobuf.Message){
            MessageProtobuf.Message message = (MessageProtobuf.Message) msg;
            if(MessageType.HEARTBEAT_PING == message.getHeader().getType()){
                //send back pong
                ctx.writeAndFlush(MessageBuilder.buildHeartbeatPongMessage(message.getHeader().getId()));
                logger.info("header of session or status messages from access or transfer layer: " + message.getHeader().toString());
                logger.info("body of session or status messages form access or transfer layer: " + message.getBody().toString());
            }
            else if(MessageType.AUTH == message.getHeader().getType()){
                //Maintain access session info
                //1. update the user's session in session container
                Map<String, Object> data = new HashMap<>(3);
                data.put(SessionManagement.SESSION_CONTEXT, ctx);
                data.put(SessionManagement.SESSION, message);
                data.put(SessionManagement.BUSI_SERVER, this.busServer);
                SessionManagement.getInstanct().doBusiness(data);
                //2. update the user's status ('online') in status container and broadcast the status to everyone who is
                // in the same group with him.
                StatusManagement.getInstance().doBusiness(data);
            }
            else if(MessageType.STATUS == message.getHeader().getType()) {
                //Maintain user online status
                //1. update the user's status in container
                //2. send the user's latest status to everyone who is in the same group with him.
                Map<String, Object> data = new HashMap<>(3);
                data.put(SessionManagement.SESSION_CONTEXT, ctx);
                data.put(SessionManagement.SESSION, message);
                data.put(SessionManagement.BUSI_SERVER, this.busServer);

                StatusManagement.getInstance().doBusiness(data);
            }
            else if(MessageType.IM == message.getHeader().getType()) {
                //TODO: send the im message to the receipt
                //1. find receipt in current cluster first.
                //2. find receipt in other clusters second if the person cannot be found in step 1.
                //3. mark the message as offline message if the person cannot be found in step 2.
                //4. save the offline message.

                Set<Object> session = SessionManagement.getInstanct().retrieve(message.getHeader().getFrom(), String.valueOf(message.getHeader().getTenantID()));
                for(Object sessionData: session){
                    String sessionD = (String)sessionData;
                    String[] sessionDataArray=sessionD.split(",");
                    String sessionID=sessionDataArray[1];
                    InnerClient client = busServer.getInnerClients().get(Busi.CLUSTER_TAG_ACCESS);
                    //send back the message to user himself temporarily
                    client.sendMessage(message, busServer.CLUSTER_TAG_ACCESS);
                }
            }
            else {
                //TODO: send the other type message. it is not necessary to mark the message as offline if
                // the message cannot be sent.
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }
}
